package com.dd.common.utils;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 列表工具类
 * 提供列表操作、数据转换、树形结构处理等功能
 */
public class ListUtils {

    private ListUtils() {
        // 工具类防止实例化
        throw new IllegalStateException("Utility class");
    }


    /**
     * 将扁平的 ListMap<String, Object> 转为树形结构
     * 使用 Map 的好处是允许用户将查出来的实体类列表提前map()转换，如取掉is_deleted字段
     * 此时的 Map 相当于临时的 VO
     *
     * @param list  扁平列表，每个元素是 Map<String, Object>
     * @param id    节点唯一标识字段名，如 "id"
     * @param pid   父节点字段名，如 "pid" 或 "parentId"
     * @param child 子节点集合字段名，如 "children"
     * @return 树形结构的 List<Map<String, Object>>
     *
     * @code 示例用法：
     * <pre>{@code
     *     List<Map < String, Object>> listMap = list.stream()
     *                 .map(obj -> {
     *                     Map<String, Object> map = new HashMap<>();
     *                     map.put("id", obj.getId());
     *                     map.put("parentId", obj.getParentId());
     *                     map.put("name", obj.getFolderName());
     *                     return map;
     *                 })
     *                 .collect(Collectors.toList());
     *
     *     ListUtils.listToTree(listMap, "id", "parentId", "children")
     * }</pre>
     *
     */
    public static List<Map<String, Object>> listToTree(
            List<Map<String, Object>> list,
            String id,
            String pid,
            String child) {

        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }

        List<Map<String, Object>> result = new ArrayList<>();
        Map<Object, Map<String, Object>> nodeMap = new HashMap<>();

        // 构建映射：id -> 节点
        for (Map<String, Object> node : list) {
            Object nodeId = node.get(id);
            nodeMap.put(nodeId, node);
        }

        // 构建树形结构
        for (Map<String, Object> node : list) {
            Object parentId = node.get(pid);

            // 如果父ID为空，或父节点不存在，则为根节点
            if (parentId == null || "".equals(parentId) || !nodeMap.containsKey(parentId)) {
                result.add(node);
            } else {
                Map<String, Object> parentNode = nodeMap.get(parentId);
                // 获取子列表
                @SuppressWarnings("unchecked")
                List<Map<String, Object>> children = (List<Map<String, Object>>) parentNode.get(child);
                if (children == null) {
                    children = new ArrayList<>();
                    parentNode.put(child, children);
                }
                children.add(node);
            }
        }

        return result;
    }

    /**
     * JSONArray转树形结构
     *
     * @param arr JSON数组
     * @param id 主键字段名
     * @param pid 父级字段名
     * @param child 子级字段名
     * @return 树形结构的JSONArray
     *
     * @apiNote
     * <p>List 转 JSONArray：
     * <pre>{@code
     *     // fastjaon2
     *     // 对象列表，核心：先转成json字符串，再解析成json数组
     *     List<User> userList = userService.list();
     *     JSONArray arr = JSON.parseArray(JSON.toJSONString(list))
     *     // 字符串列表
     *     List<String> simpleList = Arrays.asList("a", "b", "c");
     *     JSONArray jsonArray1 = JSONArray.of(simpleList.toArray());
     *
     *     // Jackson 转换为 JSON 字符串或 ArrayNode
     *     ObjectMapper mapper = new ObjectMapper();
     *     List<User> users = userService.list();
     *     // 转成 JSON 字符串
     *     String json = mapper.writeValueAsString(users);
     *     // 或者转成 ArrayNode（类似 JSONArray）Jackson 没有叫 JSONArray 的类
     *     ArrayNode arrayNode = mapper.valueToTree(users);
     * }</pre>
     * </p>
     */
    public static JSONArray listToTree(JSONArray arr, String id, String pid, String child) {
        if (arr == null || arr.isEmpty()) {
            return new JSONArray();
        }

        JSONArray result = new JSONArray();
        Map<String, JSONObject> nodeMap = new HashMap<>();

        // 构建节点映射
        for (Object item : arr) {
            JSONObject node = (JSONObject) item;
            String nodeId = node.getString(id);
            nodeMap.put(nodeId, node);
        }

        // 构建树形结构
        for (Object item : arr) {
            JSONObject node = (JSONObject) item;
            String parentId = node.getString(pid);

            if (StringUtils.isBlank(parentId) || !nodeMap.containsKey(parentId)) {
                result.add(node);
            } else {
                JSONObject parentNode = nodeMap.get(parentId);
                JSONArray children = parentNode.getJSONArray(child);
                if (children == null) {
                    children = new JSONArray();
                    parentNode.put(child, children);
                }
                children.add(node);
            }
        }

        return result;
    }

    /**
     * List去重,保持原顺序
     *
     * @param <T> 泛型类型
     * @param list 待去重列表
     * @return 去重后的列表
     */
    public static <T> List<T> uniqueBySetOrder(List<T> list) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }

        Set<T> seen = new LinkedHashSet<>();
        List<T> result = new ArrayList<>();

        for (T item : list) {
            if (seen.add(item)) {
                result.add(item);
            }
        }
        return result;
    }

    /**
     * List去重,可能打乱顺序但性能更好
     *
     * @param <T> 泛型类型
     * @param list 待去重列表
     * @return 去重后的列表
     */
    public static <T> List<T> uniqueBySet(List<T> list) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        return new ArrayList<>(new HashSet<>(list));
    }

    /**
     * 使用Stream API去重（Java8+推荐方式）
     *
     * @param <T> 泛型类型
     * @param list 待去重列表
     * @return 去重后的列表
     */
    public static <T> List<T> distinct(List<T> list) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        return list.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 列表转字符串
     *
     * @param list 列表
     * @param separator 分隔符
     * @return 拼接后的字符串
     */
    public static String listToString(List<?> list, String separator) {
        if (list == null || list.isEmpty()) {
            return "";
        }
        return list.stream()
                .map(Object::toString)
                .collect(Collectors.joining(separator));
    }

    /**
     * Long列表转字符串
     *
     * @param list 列表 [1, 2, 4] -> 1,2,3
     * @param separator 分割符号
     * @return String
     */
    public static String listToStringByLong(List<Long> list, String separator) {
        return listToString(list, separator);
    }

    /**
     * Integer列表转字符串
     *
     * @param list 列表 [1, 2, 4] -> 1,2,3
     * @param separator 分割符号
     * @return String
     */
    public static String listToStringByInt(List<Integer> list, String separator) {
        return listToString(list, separator);
    }

    /**
     * String列表转字符串
     *
     * @param list 列表 ["1", "2", "3"] -> 1,2,3
     * @param separator 分割符号
     * @return String
     */
    public static String listToStringByStr(List<String> list, String separator) {
        return listToString(list, separator);
    }

    /**
     * 字符串分割为Long列表
     *
     * @param str 字符串
     * @param regex 分隔符
     * @return List<Long>
     */
    public static List<Long> stringToListAsLong(String str, String regex) {
        if (StringUtils.isBlank(str)) {
            return Collections.emptyList();
        }

        return Arrays.stream(str.split(regex))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .map(Long::valueOf)
                .collect(Collectors.toList());
    }

    /**
     * 字符串分割为Integer列表
     *
     * @param str 字符串
     * @param regex 分隔符
     * @return List<Integer>
     */
    public static List<Integer> stringToListAsInt(String str, String regex) {
        if (StringUtils.isBlank(str)) {
            return Collections.emptyList();
        }

        return Arrays.stream(str.split(regex))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .map(Integer::valueOf)
                .collect(Collectors.toList());
    }

    /**
     * 字符串分割为String列表
     *
     * @param str 字符串
     * @param regex 分隔符
     * @return List<String>
     */
    public static List<String> stringToListAsStr(String str, String regex) {
        if (StringUtils.isBlank(str)) {
            return Collections.emptyList();
        }

        return Arrays.stream(str.split(regex))
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .collect(Collectors.toList());
    }

    /**
     * 字符串转列表Map(Long)
     *
     * @param s 字符串
     * @return List<Map<String, Long>>
     */
    public static List<Map<String, Long>> stringToListAsMapLong(String s) {
        if (StringUtils.isEmpty(s)) {
            return Collections.emptyList();
        }
        Type type = new TypeToken<List<Map<String, Long>>>() {}.getType();
        return JSON.parseObject(s, type);
    }

    /**
     * 字符串转列表Map(Integer)
     *
     * @param s 字符串
     * @return List<Map<String, Integer>>
     */
    public static List<Map<String, Integer>> stringToListAsMapInt(String s) {
        if (StringUtils.isEmpty(s)) {
            return Collections.emptyList();
        }
        Type type = new TypeToken<List<Map<String, Integer>>>() {}.getType();
        return JSON.parseObject(s, type);
    }

    /**
     * 字符串转列表Map(Object)
     *
     * @param s 字符串
     * @return List<Map<String, Object>>
     */
    public static List<Map<String, Object>> stringToListAsMapObj(String s) {
        if (StringUtils.isEmpty(s)) {
            return Collections.emptyList();
        }
        Type type = new TypeToken<List<Map<String, Object>>>() {}.getType();
        return JSON.parseObject(s, type);
    }

    /**
     * 字符串转列表Map(String)
     *
     * @param s 字符串
     * @return List<Map<String, String>>
     */
    public static List<Map<String, String>> stringToListAsMapStr(String s) {
        if (StringUtils.isEmpty(s)) {
            return Collections.emptyList();
        }
        Type type = new TypeToken<List<Map<String, String>>>() {}.getType();
        return JSON.parseObject(s, type);
    }

    /**
     * 对象转Long列表
     *
     * @param object 对象
     * @return List<Long>
     */
    public static List<Long> objectToListAsLong(Object object) {
        if (object == null) {
            return Collections.emptyList();
        }
        Type type = new TypeToken<List<Long>>() {}.getType();
        return JSON.parseObject(JSONObject.toJSONString(object), type);
    }

    /**
     * 对象转Integer列表
     *
     * @param object 对象
     * @return List<Integer>
     */
    public static List<Integer> objectToListAsInt(Object object) {
        if (object == null) {
            return Collections.emptyList();
        }
        Type type = new TypeToken<List<Integer>>() {}.getType();
        return JSON.parseObject(JSONObject.toJSONString(object), type);
    }

    /**
     * 对象转String列表
     *
     * @param object 对象
     * @return List<String>
     */
    public static List<String> objectToListAsStr(Object object) {
        if (object == null) {
            return Collections.emptyList();
        }
        Type type = new TypeToken<List<String>>() {}.getType();
        return JSON.parseObject(JSONObject.toJSONString(object), type);
    }

    /**
     * 判断列表是否为空
     *
     * @param list 待检查列表
     * @return 是否为空
     */
    public static boolean isEmpty(Collection<?> list) {
        return list == null || list.isEmpty();
    }

    /**
     * 判断列表是否非空
     *
     * @param list 待检查列表
     * @return 是否非空
     */
    public static boolean isNotEmpty(Collection<?> list) {
        return !isEmpty(list);
    }

    /**
     * 分页列表
     *
     * @param <T> 泛型类型
     * @param list 原始列表
     * @param page 页码
     * @param size 每页大小
     * @return 分页后的列表
     */
    public static <T> List<T> paginate(List<T> list, int page, int size) {
        if (isEmpty(list)) {
            return Collections.emptyList();
        }

        int total = list.size();
        int fromIndex = (page - 1) * size;
        if (fromIndex >= total) {
            return Collections.emptyList();
        }

        int toIndex = Math.min(fromIndex + size, total);
        return list.subList(fromIndex, toIndex);
    }

    /**
     * 列表分组
     *
     * @param <T> 元素类型
     * @param <K> 分组键类型
     * @param list 原始列表
     * @param classifier 分组函数
     * @return 分组后的Map
     */
    public static <T, K> Map<K, List<T>> groupBy(List<T> list, java.util.function.Function<T, K> classifier) {
        if (isEmpty(list)) {
            return Collections.emptyMap();
        }
        return list.stream().collect(Collectors.groupingBy(classifier));
    }

    /**
     * 列表过滤
     *
     * @param <T> 元素类型
     * @param list 原始列表
     * @param predicate 过滤条件
     * @return 过滤后的列表
     */
    public static <T> List<T> filter(List<T> list, java.util.function.Predicate<T> predicate) {
        if (isEmpty(list)) {
            return Collections.emptyList();
        }
        return list.stream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * 列表映射
     *
     * @param <T> 源类型
     * @param <R> 目标类型
     * @param list 原始列表
     * @param mapper 映射函数
     * @return 映射后的列表
     */
    public static <T, R> List<R> map(List<T> list, java.util.function.Function<T, R> mapper) {
        if (isEmpty(list)) {
            return Collections.emptyList();
        }
        return list.stream().map(mapper).collect(Collectors.toList());
    }

    /**
     * 获取列表的第一个元素
     *
     * @param <T> 元素类型
     * @param list 列表
     * @return 第一个元素，如果列表为空返回null
     */
    public static <T> T first(List<T> list) {
        return isEmpty(list) ? null : list.get(0);
    }

    /**
     * 获取列表的最后一个元素
     *
     * @param <T> 元素类型
     * @param list 列表
     * @return 最后一个元素，如果列表为空返回null
     */
    public static <T> T last(List<T> list) {
        return isEmpty(list) ? null : list.get(list.size() - 1);
    }
}